﻿using HmmmIDE.Intellisense;
using System;
using System.Windows.Input;
using System.Threading;
using MahApps.Metro.Controls;

namespace HmmmIDE.Debug
{
    /// <summary>
    /// Interaction logic for Debugger.xaml
    /// </summary>
    public partial class Debugger : MetroWindow
    {
        #region Field
        Simulator _Simulator;
        private bool _CanContinue = true;
        private AutoResetEvent _ShouldContinue;
        private Register[] RegistersData { get { return DebugService.Registers; } }
        private ICSharpCode.AvalonEdit.TextEditor _hmmmEditor;
        public static readonly RoutedUICommand Continue = new RoutedUICommand("Continue the simulator", "Continue", typeof(Debugger));
        public static readonly RoutedUICommand ExecuteToEnd = new RoutedUICommand("Execute To End", "ExecuteToEnd", typeof(Debugger));
        #endregion

        #region Constructor
        public Debugger(Instruction[] instrctions, ICSharpCode.AvalonEdit.TextEditor editor)
        {


            _Simulator = new Simulator(instrctions);
            InitializeComponent();
            RegisterList.ItemsSource = DebugService.Registers;

            _ShouldContinue = _Simulator._ShouldContinue;

            // hook events
            _Simulator.CommandExecuted += UpdateUIEvent;
            _Simulator.SimulationFinished += FinishUIEvent;
            _Simulator.SimulationFinished += SetExecutionStateEvent;

            this._hmmmEditor = editor;

            // run simulator
            _Simulator.Run();
        }
        #endregion

        #region Events
        private void CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = this._CanContinue;
        }

        private void ContinueDebug(object sender, ExecutedRoutedEventArgs e)
        {
            _ShouldContinue.Set();
        }

        private void StopDebugging(object sender, ExecutedRoutedEventArgs e)
        {
            _Simulator.Stop();  // terminate the debugging
        }

        private void UpdateUIEvent(object sender, Simulator.SimulatorEventArgs e)
        {
            Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate()
            {

                // Not a good way to update data. But I got some issues with binding data
                RegisterList.ItemsSource = null;
                RegisterList.ItemsSource = RegistersData;
                lblIndicator.Content = string.Format("Line To Be Executed {0}. PC: {1}", e.LineNumber, e.PC);
                var line = _hmmmEditor.Document.Lines[e.LineNumber - 1];

                // show update in HMMM editor
                _hmmmEditor.Select(line.Offset, line.Length);
            }
        ));
        }

        private void FinishUIEvent(object sender, EventArgs e)
        {
            Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate()
            {

                // Not a good way to update data. But I got some issues with binding data
                RegisterList.ItemsSource = null;
                RegisterList.ItemsSource = RegistersData;
                lblIndicator.Content = string.Format("Execution Finished");
            }
        ));
        }


        private void SetExecutionStateEvent(object sender, EventArgs e)
        {
            this._CanContinue = false;   // Disable the debug button
        }

        private void Debugger_Closed(object sender, EventArgs e)
        {
            _Simulator.Stop();   // terminate the thread
            IE.Close();
            _hmmmEditor.IsReadOnly = false;
        }

        private void ExecuteToEndMethod(object sender, ExecutedRoutedEventArgs e)
        {
            _ShouldContinue.Set();
            DebugService.ShouldStop = false;
        }


        #endregion
    }
}
